#include <Windows.h>
#include <tchar.h>
#include "resource.h"

struct SThreadInfo
{
	HWND	hEdit;
	bool	bSync;
	CRITICAL_SECTION* pcs;
};

void AddText(HWND hEdit, TCHAR* szFormat, ...)
{
	va_list vaList;
	va_start(vaList, szFormat);
	TCHAR szBuff[1024 * 20];
	GetWindowText(hEdit, szBuff, _countof(szBuff));
	_vstprintf(_tcschr(szBuff, 0), szFormat, vaList);
	SetWindowText(hEdit, szBuff);
	va_end(vaList);
	SendMessage(hEdit, WM_VSCROLL, SB_BOTTOM, 0);

	return;
}

DWORD CALLBACK AsyncThreadProc(LPVOID lpData)
{
	SThreadInfo* pThreadInfo = (SThreadInfo*)lpData;
	TCHAR szBuf[1024 * 10] = {0};
	for (int ii = 0; ii < 100; ii++)
	{
		AddText(pThreadInfo->hEdit, _T("Thread(0x%0X) wrote %d\r\n"), GetCurrentThreadId(), ii + 1);
		Sleep(1);
	}
	return 0;
}

DWORD CALLBACK SyncThreadProc(LPVOID lpData)
{
	SThreadInfo* pThreadInfo = (SThreadInfo*)lpData;
	EnterCriticalSection(pThreadInfo->pcs);
		
	TCHAR szBuf[1024 * 10] = {0};
	for (int ii = 0; ii < 100; ii++)
	{
		AddText(pThreadInfo->hEdit, _T("Thread(0x%0X) wrote %d\r\n"), GetCurrentThreadId(), ii + 1);
		Sleep(1);
	}
	LeaveCriticalSection(pThreadInfo->pcs);
	return 0;
}

DWORD CALLBACK CreateThreadProc(LPVOID lpData)
{
	SThreadInfo* pThreadInfo = (SThreadInfo*)lpData;
	HANDLE hThreads[2];
	
	LPTHREAD_START_ROUTINE ThreadProc = pThreadInfo->bSync ? SyncThreadProc : AsyncThreadProc;
	for (int ii = 0; ii < 2; ii++)
	{
		hThreads[ii] = CreateThread(NULL, 0, ThreadProc, (LPVOID)pThreadInfo, 0, NULL);
	}
	
	WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
	for (int ii = 0; ii < 2; ii++)
	{
		CloseHandle(hThreads[ii]);
		hThreads[ii] = NULL;
	}
	

	return 0;
}

int CALLBACK DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	static SThreadInfo ThreadInfo;
	static CRITICAL_SECTION cs;
	switch (nMsg)
	{		
		case WM_INITDIALOG:
		{
			SetWindowText(hDlg, _T("Demo0089"));

			UINT nWidth		= GetSystemMetrics(SM_CXSCREEN);
			UINT nHeight	= GetSystemMetrics(SM_CYSCREEN);
			RECT rtClient;
			GetClientRect(hDlg, &rtClient);
			SetWindowPos(hDlg, NULL, (nWidth - (rtClient.right - rtClient.left)) / 2, (nHeight - (rtClient.bottom - rtClient.top)) / 2, 0, 0, SWP_NOSIZE);
				
			InitializeCriticalSection(&cs);		
			break;
		}
		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDC_BTNASYNC:
				case IDC_BTNSYNC:
				{
					SetDlgItemText(hDlg, IDC_EDTINFO, _T(""));
					ThreadInfo.hEdit	= GetDlgItem(hDlg, IDC_EDTINFO);
					ThreadInfo.bSync	= (LOWORD(wParam) == IDC_BTNSYNC) ? true : false;
					ThreadInfo.pcs		= &cs;
					CreateThread(NULL, 0, CreateThreadProc, (LPVOID)&ThreadInfo, 0, NULL);
					break;
				}
			}

			break;
		}
		case WM_CLOSE:
		{
			DeleteCriticalSection(&cs);

			PostQuitMessage(0);
			break;
		}
	}

	return 0;
}

BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);

	return TRUE;
}